package com.itheima.d8_stream;
import java.util.*;
import java.util.stream.Collectors;
import java.util.stream.Stream;

/**
 * 目标：Stream流的终结方法
 * 终结方法指的是调用完成后，不会返回新Stream了，没法继续使用流了。
 *
 * Stream提供的常用终结方法
 * void forEach(Consumer action)                    对此流运算后的元素执行遍历
 * long count()                                     统计此流运算后的元素个数
 * Optional<T>max(Comparator<? super T>comparator)  获取此流运算后的最大值元素
 * Optional<T>min(Comparator<? super T>comparator)  获取此流运算后的最小值元素
 *
 * 收集Stream流：就是把Stream流操作后的结果转回到集合或者数组中去返回。
 * Stream流：方便操作集合/数组的手段；   集合/数组：才是开发中的目的。
 * Collectors工具类提供了具体的收集方式
 * public static <T> Collector toList()        把元素收集到List集合中
 * public static <T> Collector toSet()         把元素收集到Set集合中
 * public static  Collector toMap(Function keyMapper , Function valueMapper)   把元素收集到Map集合中
 *
 * 疑惑：
 * 以前集合内元素指定排序规则是用下面的两种方式，但是现在是用stream流调用sort方法用lambda的方式
 *  * 方式一
 *  *      让自定义的类（如学生类）实现Comparable接口，重写里面的compareTo方法来指定比较规则。
 *  * 方式二
 *  *      public TreeSet(Comparator<? super E> comparator)
 *  *      通过调用TreeSet集合有参数构造器，可以设置Comparator对象（比较器对象，用于指定比较规则。
 *
 *  疑惑：我把max的比较规则改为降序的排序，输出的是紫霞内容，是最小值身高对象
 */
public class StreamTest4 {
    public static void main(String[] args) {
        List<Student> students = new ArrayList<>();
        Student s1 = new Student("蜘蛛精", 26, 172.5);
        Student s2 = new Student("蜘蛛精", 26, 172.5);
        Student s3 = new Student("紫霞", 23, 167.6);
        Student s4 = new Student("白晶晶", 25, 169.0);
        Student s5 = new Student("牛魔王", 35, 183.3);
        Student s6 = new Student("牛夫人", 34, 168.5);
        Collections.addAll(students, s1, s2, s3, s4, s5, s6);
        // 需求1：请计算出身高超过168的学生有几人。
        //count方法返回一个long类型数据，未返回新的stream流，是终结方法
        long size = students.stream().filter(s -> s.getHeight() > 168).count();
        System.out.println(size);

        System.out.println("---------------max-------------");
        // 需求2：请找出身高最高的学生对象，并输出。
        // 指定max的比较规则为身高，然后返回符合条件的学生对象，用Optional<student>容器装起来返回
        //疑惑，视频里面没说明，为什么是前面用来升序的排序规则，可以动作max的比较规则
        Student s = students.stream().max((o1, o2) -> Double.compare(o1.getHeight(), o2.getHeight())).get();
        System.out.println(s);
        System.out.println("----------疑惑：我把max的比较规则改为降序的排序，输出的是紫霞内容，是最小值身高对象");
        //自己写一写
        Student zeng1 = students.stream().max(new Comparator<Student>() {
            @Override
            public int compare(Student o1, Student o2) {
                return Double.compare(o2.getHeight(),o1.getHeight());
            }
        }).get();
        System.out.println(zeng1);


        System.out.println("-----------------min------------------");
        // 需求3：请找出身高最矮的学生对象，并输出。
        Student ss = students.stream().min((o1, o2) -> Double.compare(o1.getHeight(), o2.getHeight())).get();
        System.out.println(ss);

        System.out.println("---------------收集stream流到list集合----------");
       /*
        // 流只能收集一次。
        //易错点：把students.stream().filter(a -> a.getHeight() > 170)过滤出来的stream流单独拿出来，然后再套进去用
        Stream<Student> studentStream = students.stream().filter(a -> a.getHeight() > 170);
        //这个studentStream用第一次的时候不会报错，正常输出
        List<Student> shiYan = studentStream.collect(Collectors.toList());
        System.out.println(shiYan);

        //但是studentStream第二次使用的时候就会报错,IllegalStateException:stream has already been operated upon or closed
        //因为studentStream流在前面studentStream.collect(Collectors.toList());已经收集过一次，就关闭了，下面再用的话，这个流就已经关闭掉了没有了
        //还可以类比理解为迭代器，studentStream已经指针移到最后面去了，这里再去收集就已经没有了
        // 流只能收集一次。
        Set<Student> shiYan2 = studentStream.collect(Collectors.toSet());
        System.out.println(shiYan2);

        */

        // 需求4：请找出身高超过170的学生对象，并放到一个新集合中去返回。
        //符合条件的学生对象收集到list集合中
        List<Student> students1 = students.stream().filter(a -> a.getHeight() > 170).collect(Collectors.toList());
        System.out.println(students1);

        System.out.println("-------------收集stream流到set集合------------");
        //符合条件的学生对象收集到set集合中,set集合不允许重复元素
        // * 结论：如果希望Set集合认为2个内容一样的对象是重复的，
        // *      保证内容一样的对象计算出来的哈希值相同：重写对象的hashCode()
        // *      计算出来的底层数组索引值相同后，保证调用equals方法判断的是新老元素的内容：重写equals()方法
        Set<Student> students2 = students.stream().filter(a -> a.getHeight() > 170).collect(Collectors.toSet());
        System.out.println(students2);

        System.out.println("=====自己写一写，疑惑：stream流进行sort方法排序后，再收集到set集合，但是set集合没有排序，实际输出结果也没有排序=======================");
        Set<Student> zeng11 = students.stream().filter(a->a.getAge()>20)
                .sorted(((o1, o2) -> o1.getAge()- o2.getAge()))
                        .collect(Collectors.toSet());
        System.out.println(zeng11);

        System.out.println("------------------按年龄升序，那我不放到set集合-------------");
        students.stream().filter(a->a.getAge()>20).sorted(((o1, o2) -> o1.getAge()-o2.getAge()))
                        .forEach(a-> System.out.println(a));


        System.out.println("------------收集stream流到map集合-------------");
        // 需求5：请找出身高超过170的学生对象，并把学生对象的名字和身高，存入到一个Map集合返回。
        //需要声明是把什么作为返回的map集合的键和值
        Map<String, Double> map =
                students.stream().filter(a -> a.getHeight() > 170)
                        .distinct()     //map不会自动去除两个蜘蛛精的键，会报异常，所以要主动去重     IllegalStateException: Duplicate key 蜘蛛精
                        .collect(Collectors.toMap(a -> a.getName(), a -> a.getHeight()));
        System.out.println(map);

        System.out.println("-----------------自己试一试-----------------");
        System.out.println(students.stream().filter(q -> q.getAge() > 10).distinct()
                .collect(Collectors.toMap(q -> q.getName(), q -> q.getAge())));

        Map<String,Integer> zengjihong =
                students.stream().filter(q->q.getAge()>10)
                        .distinct()
                .collect(Collectors.toMap(q->q.getName(),q->q.getAge()));
        System.out.println(zengjihong);

        System.out.println("------------收集到一个数组中----------");
         Object[] arr = students.stream().filter(a -> a.getHeight() > 170).toArray();
        System.out.println(Arrays.toString(arr));

        //返回到一个学生对象类型的数组中：需要在toArray中声明转换为什么数组，len -> new Student[len]
        Student[] arr1 = students.stream().filter(a -> a.getHeight() > 170).toArray(len -> new Student[len]);
        System.out.println(Arrays.toString(arr1));
    }
}
